/*
 * CompactBinomial.java
 *
 * Created on January 28, 2005, 1:47 PM
 */

package com.milowski.monos.binomial;

import com.milowski.monos.*;
import com.milowski.monos.monomial.*;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.XMLException;

/**
 *
 * @author R. Alexander Milowski
 */
public class CompactBinomial implements Binomial
{
   
   short [] values;
   
   /** Creates a new instance of Binomial */
   public CompactBinomial(Monomial leadingTerm,Monomial trailingTerm) {
      this(leadingTerm.getValues(),trailingTerm.getValues());
   }
   
   public CompactBinomial(short [] leadingTerm, short [] trailingTerm) {
      values = new short[leadingTerm.length];
      for (int i=0; i<leadingTerm.length; i++) {
         values[i] = (short)(leadingTerm[i]-trailingTerm[i]);
      }
   }
   
   public CompactBinomial(int length) {
      this.values = new short[length];
   }
   
   public CompactBinomial(short [] compactValues) {
      this(compactValues.length);
      System.arraycopy(compactValues,0, values,0, values.length);
   }
   
   public short [] getValues() {
      return values;
   }
   
   public short [] getLeadingTerm() {
      short [] leading = new short[values.length];
      for (int i=0; i<leading.length; i++) {
         leading[i] = values[i]>0 ? values[i] : 0;
      }
      return leading;
   }
   
   public short [] getTrailingTerm() {
      short [] trailing = new short[values.length];
      for (int i=0; i<trailing.length; i++) {
         trailing[i] = values[i]<0 ? (short)-values[i] : 0;
      }
      return trailing;
   }
   
   public void swap() {
      for (int i=0; i<values.length; i++) {
         values[i] = (short)-values[i];
      }
   }
   
   public Monomial toLeadingMonomial() {
      Monomial a = new Monomial(getLeadingTerm(),false);
      return a;
   }
   
   public Monomial toTrailingMonomial() {
      Monomial b = new Monomial(getTrailingTerm(),false);
      return b;
   }
   
   /*
   public void set(Monomial leadingTerm,Monomial trailingTerm) {
      
      leading = leadingTerm.getValues();
      trailing = trailingTerm.getValues();
   } */     
   
   public CompactBinomial toCompactBinomial() {
      return this;
   }

   public boolean equals(Object other) {
      if (!(other instanceof Binomial)) {
         return true;
      }
      if (other instanceof CompactBinomial) {
         CompactBinomial cother = (CompactBinomial)other;
         short [] ovalues = cother.getValues();
         if (values.length!=ovalues.length) {
            return false;
         }
         for (int i=0; i<ovalues.length; i++) {
            if (values[i]!=ovalues[i]) {
               return false;
            }
         }
      } else {
         Binomial bother = (Binomial)other;
         short [] otherLeading = bother.getLeadingTerm();
         short [] otherTrailing = bother.getTrailingTerm();
         if (values.length!=otherLeading.length) {
            return false;
         }
         for (int i=0; i<otherLeading.length; i++) {
            if (values[i]>=0) {
               if (values[i]!=otherLeading[i] || otherTrailing[i]!=0) {
                  return false;
               }
            } else {
               if ((-values[i])!=otherTrailing[i] || otherLeading[i]!=0) {
                  return false;
               }
            }
         }
      }
      return true;
   }
   
   public String format(LexOrder order)
   {
      StringBuffer leading = new StringBuffer();
      StringBuffer trailing = new StringBuffer();
      boolean startedLeading = false;
      boolean startedTrailing = false;
      for (int i=0; i<values.length; i++) {
         if (values[i]>0) {
            if (startedLeading) {
               leading.append('*');
            }
            startedLeading = true;
            leading.append((String)order.get(i));
            if (values[i]!=1) {
               leading.append('^');
               leading.append(Short.toString(values[i]));
            }
         } else if (values[i]<0) {
            if (startedTrailing) {
               trailing.append('*');
            }
            startedTrailing = true;
            trailing.append((String)order.get(i));
            if (values[i]!=(-1)) {
               trailing.append('^');
               trailing.append(Integer.toString(-values[i]));
            }
         }
      }
      if (!startedLeading) {
         leading.append("1");
      }
      if (!startedTrailing) {
         trailing.append("1");
      }
      return leading.toString()+' '+trailing.toString();
   }
   
   public String toString() {
      StringBuffer sb = new StringBuffer();
      sb.append("(list->compact-binomial ");
      for (int i=0; i<values.length; i++) {
         if (i!=0) {
            sb.append(' ');
         }
         sb.append(values[i]);
      }
      sb.append(')');
      return sb.toString();
   }
   
   public static CompactBinomial toBinomial(LexOrder order,String leading,String trailing) 
      throws FormatException
   {
      CompactBinomial b = new CompactBinomial(order.size());
      Monomial.parseMonomial(order,b.getValues(),leading);
      Monomial.parseMonomial(order,b.getValues(),trailing,true);
      return b;
   }
   
   public void toXML(ItemDestination dest) throws XMLException {
      toXML(InfosetFactory.getDefaultInfoset().createItemConstructor(),dest);
   }

   public void toXML(ItemConstructor constructor, ItemDestination dest) throws XMLException {
      dest.send(constructor.createElement(XML.cbinomialName));
      StringBuffer sb = new StringBuffer();
      for (int i=0; i<values.length; i++) {
         if (i!=0) {
            sb.append(' ');
         }
         sb.append(values[i]);
      }
      dest.send(constructor.createCharacters(sb.toString()));
      dest.send(constructor.createElementEnd(XML.cbinomialName));
   }

   
}
